package com.msh.automatic.android.api.controller.pub;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.msh.automatic.android.api.entity.ActivationCode;
import com.msh.automatic.android.api.entity.Device;
import com.msh.automatic.android.api.mapper.ActivationCodeMapper;
import com.msh.automatic.android.api.mapper.DeviceMapper;
import com.msh.automatic.android.api.util.JwksUtil;
import com.msh.automatic.android.api.util.RetUtil;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.RSASSASigner;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import io.swagger.annotations.ApiOperation;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.io.UnsupportedEncodingException;
import java.util.Date;

@Slf4j
@RestController("p_device")
@RequestMapping("/p/device")
public class DeviceController {

    @Resource
    JwksUtil jwksUtil;
    @Resource
    DeviceMapper deviceMapper;
    @Resource
    ActivationCodeMapper activationCodeMapper;

    @ApiOperation(value = "设备注册")
    @RequestMapping(value = "/register", method = RequestMethod.POST)
    public Object register(@RequestBody Device params) throws UnsupportedEncodingException {
        Device device = deviceMapper.selectById(params.getId());
        if(device == null){
            device = new Device();
            device.setId(params.getId());
            device.setModel(params.getModel());
            device.setBrand(params.getBrand());
            device.setDevice(params.getDevice());
            device.setManufacturer(params.getManufacturer());
            device.setRelease(params.getRelease());
            device.setSdkInt(params.getSdkInt());
            deviceMapper.insert(device);
        }
        return RetUtil.success(device);
    }

    @ApiOperation(value = "设备激活")
    @RequestMapping(value = "/activation", method = RequestMethod.POST)
    public Object activation(@RequestBody Device params) throws UnsupportedEncodingException, JOSEException {
        ActivationCode activationCode = activationCodeMapper.selectById(params.getActivationCode());
        if(activationCode==null){
            return RetUtil.error("激活码不存在");
        }
        if(activationCode.getDeviceId() != null && !activationCode.getDeviceId().equals(params.getId())){
            return RetUtil.error("激活码已使用");
        }
        Device device = deviceMapper.selectById(params.getId());
        if(device == null){
            return RetUtil.error("设备不存在");
        }
        device.setActivationCode(activationCode.getId());
        device.setActivationTime(new Date());
        if(device.getExpirationTime() == null || !com.msh.automatic.android.api.util.DateUtil.isDateTodayOrAfter(device.getExpirationTime())){
            device.setExpirationTime(DateUtil.offset(new Date(), DateField.DAY_OF_YEAR,activationCode.getValidityDay()));
        }else{
            device.setExpirationTime(DateUtil.offset(device.getExpirationTime(), DateField.DAY_OF_YEAR,activationCode.getValidityDay()));
        }
        activationCode.setDeviceId(device.getId());
        activationCodeMapper.updateById(activationCode);
        // 构造声明（payload）
        JWTClaimsSet.Builder build = new JWTClaimsSet.Builder()
                .subject(device.getId())                    // 用户标识（sub）
                .issuer("msh")                   // 签发者（iss）
                .audience("msh")                // 接收方（aud）
                .expirationTime(device.getExpirationTime())             // 过期时间
                .issueTime(new Date());                             // 签发时间（iat）
        // 使用 RSA 私钥进行签名
        JWSSigner signer = new RSASSASigner(jwksUtil.getKey().toPrivateKey());

        SignedJWT signedJWT = new SignedJWT(
                new JWSHeader.Builder(JWSAlgorithm.RS256)
                        .keyID(jwksUtil.getKey().getKeyID())
                        .type(JOSEObjectType.JWT)
                        .build(),
                build.build()
        );

        signedJWT.sign(signer);
        device.setToken(signedJWT.serialize());
        deviceMapper.updateById(device);
        return RetUtil.success(device);
    }
}
